#![feature(test)]

extern crate test;
extern crate cook;

use test::Bencher;
use cook::math::big::Nat;

#[bench]
fn prime_validate(b: &mut Bencher) {
    b.iter(|| {
        let cases = [
            "2",
            "3",
            "5",
            "7",
            "11",
            "13756265695458089029",
            "13496181268022124907",
            "10953742525620032441",
            "17908251027575790097",

            // https://golang.org/issue/638
            "18699199384836356663",

            "98920366548084643601728869055592650835572950932266967461790948584315647051443",
            "94560208308847015747498523884063394671606671904944666360068158221458669711639",

            // https://primes.utm.edu/lists/small/small3.html
            "449417999055441493994709297093108513015373787049558499205492347871729927573118262811508386655998299074566974373711472560655026288668094291699357843464363003144674940345912431129144354948751003607115263071543163",
            "230975859993204150666423538988557839555560243929065415434980904258310530753006723857139742334640122533598517597674807096648905501653461687601339782814316124971547968912893214002992086353183070342498989426570593",
            "5521712099665906221540423207019333379125265462121169655563495403888449493493629943498064604536961775110765377745550377067893607246020694972959780839151452457728855382113555867743022746090187341871655890805971735385789993",
            "203956878356401977405765866929034577280193993314348263094772646453283062722701277632936616063144088173312372882677123879538709400158306567338328279154499698366071906766440037074217117805690872792848149112022286332144876183376326512083574821647933992961249917319836219304274280243803104015000563790123",

            // ECC primes: https://tools.ietf.org/html/draft-ladd-safecurves-02
            "3618502788666131106986593281521497120414687020801267626233049500247285301239",                                                                                  // Curve1174: 2^251-9
            "57896044618658097711785492504343953926634992332820282019728792003956564819949",                                                                                 // Curve25519: 2^255-19
            "9850501549098619803069760025035903451269934817616361666987073351061430442874302652853566563721228910201656997576599",                                           // E-382: 2^382-105
            "42307582002575910332922579714097346549017899709713998034217522897561970639123926132812109468141778230245837569601494931472367",                                 // Curve41417: 2^414-17
            "6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151", // E-521: 2^521-1
        ];
        let s = 1usize;

        for &ele in cases.iter() {
            let nat = Nat::from(ele);
            nat.probably_prime(s);
        }
    });
}

#[bench]
fn nat_mul(b: &mut Bencher) {
    b.iter(|| {
        assert_eq!(&Nat::from("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff") *
                       &Nat::from("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
                   Nat::from("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeff0000000000000000000000000000000000000000000000000000000000000001"));
        assert_eq!(&Nat::from("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff") *
                       &Nat::from("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
                   Nat::from("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0000000000000000000000000000000000000000000000000000000000000001"));
        assert_eq!(&Nat::from("2938462938472983472983659726349017249287491026512746239764525612965293865296239471239874193284792387498274256129746192347") *
                       &Nat::from("298472983472983471903246121093472394872319615612417471234712061"),
                   Nat::from("877051800070821244789099242710450134536982682006837233541161511456161001386576641869116186901815671895415144768179824202865342118174193449288433467901275304066981993483906649666797167"));
        let l1 = Nat::from_str("f9058301048250fabddeabf9320480284932084552541", 16);
        let l2 = Nat::from_str("f329053910428502fabcd9230494035242429890eacb", 16);
        let m = Nat::from_str("ec882250900ba90c2088a4a5ee549ecc5152d7a50683a82daa24e03f6d6409468abf1ce1f01d9be845021f48b", 16);
        assert_eq!(&l1 * &l2, m);
        let m = Nat::from("11521922904531591643048817447554701904414021819823889996244743037378330903763518501116638828335352811871131385129455853417360623007349090150042001944696604737499160174391019030572483602867266711107136838523916077674888297896995042968746762200926853379");
        let mm = Nat::from("132754707417969709071520913953150018674028397187840392482040376246690586667563465313754728983140614311023330588338584519494816082808802757576723626979148131665716420054994459252371545991867826226044967226902943970336055338722678643684695617436438527026987305947020775148894065847620914397220804830164550914287609717627447949778761358443479465789746235738152749867139029328299380633642942992192185932412578698966382535294856314633011368627178673993077019158590397083090972027015095881618004786163717641");
        assert_eq!(&m * &m, mm);
    });
}

#[bench]
fn nat_rem(b: &mut Bencher) {
    b.iter(|| {
        let l1 = Nat::from_str("ffffffffffffff000000000000", 16);
        let l2 = Nat::from_u8(255);
        assert_eq!(&l1 % &l2, Nat::from_u8(0));
        let l1 = Nat::from_str("39025820857032850384502853503850325fa3242de121", 16);
        let l2 = Nat::from_str("2048537058358afedead392582075275", 16);
        let rem = Nat::from_str("ab9de6183b632a33dc2601ae78da14e", 16);
        assert_eq!(&l1 % &l2, rem);
        let l1 = Nat::from_str("fffffffffff32908329058205820", 16);
        let l2 = Nat::from_str("ff", 16);
        let quo = Nat::from_str("d8", 16);
        assert_eq!(&l1 % &l2, quo);
        assert_eq!(&l1 % 255u32, Some(0xd8u32));
    });
}

#[bench]
fn nat_pow_mod(b: &mut Bencher) {
    b.iter( || {
        let cases = [
            ("0", "0", "0", "1"),
            ("0", "0", "1", "0"),
            ("1", "1", "1", "0"),
            ("2", "1", "1", "0"),
            ("2", "2", "1", "0"),
            ("10", "100000000000", "1", "0"),
            ("0x8000000000000000", "2", "0", "0x40000000000000000000000000000000"),
            ("0x8000000000000000", "2", "6719", "4944"),
            ("0x8000000000000000", "3", "6719", "5447"),
            ("0x8000000000000000", "1000", "6719", "1603"),
            ("0x8000000000000000", "1000000", "6719", "3199"),
            (
                "2938462938472983472983659726349017249287491026512746239764525612965293865296239471239874193284792387498274256129746192347",
                "298472983472983471903246121093472394872319615612417471234712061",
                "29834729834729834729347290846729561262544958723956495615629569234729836259263598127342374289365912465901365498236492183464",
                "23537740700184054162508175125554701713153216681790245129157191391322321508055833908509185839069455749219131480588829346291",
            ),
            (
                "11521922904531591643048817447554701904414021819823889996244743037378330903763518501116638828335352811871131385129455853417360623007349090150042001944696604737499160174391019030572483602867266711107136838523916077674888297896995042968746762200926853379",
                "426343618817810911523",
                "444747819283133684179",
                "42",
            ),
        ];

        for ele in cases.iter() {
            let (a,b,n,res) = (Nat::from(ele.0), Nat::from(ele.1), Nat::from(ele.2), Nat::from(ele.3));
            assert_eq!(a.pow_mod(&b, &n), res, "cases=>{}", ele.0);
        }
    });
}
